import { AudioUrl, EnemyType } from "../Constant/Constant";
import BulletByEnemyFactory from "../Factory/BulletByEnemyFactory";
import EnemyFactory from "../Factory/EnemyFactory";
import UIMain from "../UI/UIMain";
import { Random } from "../Utils/Random";
import AudioManager from "./AudioManager";
import EnemyManager from "./EnemyManager";
import PlayerManager from "./PlayerManager";
import PropManager from "./PropManager";

const { ccclass, property } = cc._decorator;

/**
 * 游戏主管理类
 * 管理控制整个游戏的抽象主逻辑
 */
@ccclass
export default class GameManager extends cc.Component {
  // prefabs
  @property(cc.Prefab)
  playerPlanePrefab: cc.Prefab = null

  @property(cc.Prefab)
  enemy1Prefab: cc.Prefab = null

  @property(cc.Prefab)
  enemy2Prefab: cc.Prefab = null

  @property(cc.Prefab)
  enemy3Prefab: cc.Prefab = null

  @property(cc.Prefab)
  prop1Prefab: cc.Prefab = null

  @property(cc.Prefab)
  prop2Prefab: cc.Prefab = null

  @property(cc.Prefab)
  prop3Prefab: cc.Prefab = null

  @property(cc.Prefab)
  bulletByEnemyPrefab: cc.Prefab = null

  @property(cc.Node)
  enemyParent: cc.Node = null

  @property(cc.Node)
  playerParent: cc.Node = null

  @property(cc.Node)
  propParent: cc.Node = null

  @property(cc.RichText)
  scoreRichText: cc.RichText = null

  @property(cc.Node)
  uiNode: cc.Node = null

  // Managers
  playerManager: PlayerManager = null
  enemyManager: EnemyManager = null
  propManager: PropManager = null
  uiMain: UIMain = null

  // 游戏时间
  gameTime = 0

  // 敌机组合等级
  enemyCombLevel = 0

  // 最大道具id，用于限制高等级道具出现频率
  maxPropId = 3

  // 分数
  score = 0

  start() {
    // 启动物理碰撞
    cc.director.getCollisionManager().enabled = true
    // 初始化游戏
    this.init()
  }

  update(dt) {
  }

  /**
   * 初始化游戏
   * 防止内存泄漏，该函数只调用一次
   */
  private init() {
    // 初始化玩家飞机管理器
    this.playerManager = new PlayerManager()
    this.playerManager.init(this.playerPlanePrefab, this.playerParent)
    // 初始化敌机工厂
    EnemyFactory.init([{
      type: EnemyType.TYPE_1,
      prefab: this.enemy1Prefab
    }, {
      type: EnemyType.TYPE_2,
      prefab: this.enemy2Prefab
    }, {
      type: EnemyType.TYPE_3,
      prefab: this.enemy3Prefab
    }])
    // 初始化敌机子弹工厂
    BulletByEnemyFactory.init(this.bulletByEnemyPrefab, 4)
    // 初始化敌机管理器
    this.enemyManager = new EnemyManager()
    this.enemyManager.init(this.enemyParent)
    // 初始化道具管理器
    this.propManager = new PropManager(this.prop1Prefab, this.prop2Prefab, this.prop3Prefab, this.propParent)
    // 监听敌机销毁
    this.enemyManager.setEnemyDiedCallback((score) => {
      this.addScore(score)  // 加分
    })
    // 监听玩家销毁
    this.playerManager.setPlayerDiedCallback(() => {
      // 玩家死亡
      this.uiMain.showOverView(this.score)  // 显示结束界面
      this.resetGameData()        // 重置数据
      // 暂停音乐
      AudioManager.stopMusic()
    })
    // 监听玩家碰到Boom道具，销毁全屏敌机
    this.playerManager.setTouchBoomCallback(() => {
      console.log('TouchBoomCallback')
      this.enemyManager.destoryAllNodeCallDie()
    })
    this.initScore()

    // ui初始化
    // 获取UIMain
    this.uiMain = this.uiNode.getComponent(UIMain)
    this.uiMain.showHomeView()
    this.uiMain.startClickEventCallback = this.startGame.bind(this)
    this.uiMain.restartClickEventCallback = this.restartGame.bind(this)
  }

  /**
   * 开始游戏
   */
  private startGame() {
    // 背景音乐
    AudioManager.playMusic(AudioUrl.BGM)
    // 启动游戏计时
    this.enableGameTimeing()
    // 创建玩家飞机
    this.playerManager.createPlane()
    // 创建第一架飞机
    this.enemyManager.randomCreateEnemy1()
    // 定时随机出现敌机
    this.schedule(this.enemyManager.randomCreateEnemy1, 1.5)
    this.schedule(this.enemyManager.randomCreateEnemy2, 4, cc.macro.REPEAT_FOREVER, 5)
    this.schedule(this.enemyManager.randomCreateEnemy3, 8, cc.macro.REPEAT_FOREVER, 15)
    // 启动敌机组合模式
    this.enableEnemyComb()
    // 启动生成道具
    this.enableProp()
  }

  /**
   * 开启游戏计时
   */
  private enableGameTimeing() {
    this.gameTime = 0
    this.schedule(this.addGameTime, 1)
  }

  private addGameTime() {
    this.gameTime++
  }

  /**
   * 开启敌机组合模式
   */
  private enableEnemyComb() {
    this.enemyCombLevel = 0
    // 5s后才会出现组合1
    setTimeout(this.addEnemyLevel.bind(this), 1000 * 5)
    // 10s后才会出现组合2
    setTimeout(this.addEnemyLevel.bind(this), 1000 * 10)
    // 20s后才会出现组合3
    setTimeout(this.addEnemyLevel.bind(this), 1000 * 20)
    // 每8s随机出现一次敌机组合
    this.schedule(this.randomShowEnemyComb, 8)
  }

  /**
   * 随机出现敌机组合
   */
  private randomShowEnemyComb() {
    if (this.enemyCombLevel <= 0) {
      return
    }

    const combId = Random.getIntNum(1, this.enemyCombLevel + 1)
    // console.log('combId', combId)
    switch (combId) {
      case 1:
        this.enemyManager.showComb1()
        break;
      case 2:
        this.enemyManager.showComb2()
        break;
      case 3:
        this.enemyManager.showComb3()
        break;
    }
  }

  /**
   * 开启出现道具
   */
  private enableProp(): void {
    this.maxPropId = 3
    this.schedule(this.randomShowProp, 10, cc.macro.REPEAT_FOREVER, 5)
  }

  /**
   * 随机出现道具
   */
  private randomShowProp(): void {
    // console.log('combId', combId)
    const propId = Random.getIntNum(1, this.maxPropId + 1)
    switch (propId) {
      case 1:
        this.propManager.randomCreatePropBlue()
        this.maxPropId = 3  // 恢复可以出现的道具等级，下次生成道具允许出现最高等级的道具
        break;
      case 2:
        this.propManager.randomCreatePropRed()
        this.maxPropId = 3  // 恢复可以出现的道具等级，下次生成道具允许出现最高等级的道具
        break;
      case 3:
        this.propManager.randomCreatePropBoom()
        this.maxPropId = 2  // 最高等级的道具出现过一次后，限制下一次不会出现
        break;
    }
  }

  /**
   * 增加敌人等级，更高的等级才会显示更高的敌机组合Comb
   */
  private addEnemyLevel() {
    this.enemyCombLevel++
  }

  /**
   * 初始化分数
   */
  private initScore() {
    this.score = 0
    this.scoreRichText.string = 'S:' + this.score
  }

  /**
   * 加分数
   * @param score 增加的分数
   */
  private addScore(score) {
    this.score += score
    this.scoreRichText.string = 'S:' + this.score
  }

  /**
   * 数据重置
   */
  private resetGameData() {
    // 数据重置
    this.unschedule(this.addGameTime)
    this.unschedule(this.randomShowEnemyComb)
    this.unschedule(this.enemyManager.randomCreateEnemy1)
    this.unschedule(this.enemyManager.randomCreateEnemy2)
    this.unschedule(this.enemyManager.randomCreateEnemy3)
    this.unschedule(this.randomShowProp)
    this.enemyManager.destroyAllNode()
    this.initScore()  // 积分重置
  }

  /**
   * 重新开始游戏
   */
  private restartGame() {
    // 开始游戏
    this.startGame()
  }
}
